﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using Zellularautomat.Structures;
using Model;

namespace Zellularautomat
{
	public partial class FormMain : Form
	{
		private Controller controller;
		private FormPreferences formPreferences;
		private List<CellDefinition> cellTypes;
		private Dictionary<string, Color> colorsForCells;
		private Preferences preferences;
		private Cell[,] cells;
		private int cellEdgeLength;

		public FormMain()
		{
			InitializeComponent();
			controller = new Controller();
			controller.StepCalculated += controller_StepCalculated;
			formPreferences = new FormPreferences(controller);
		}

		#region Events

		private void FormMain_Load(object sender, EventArgs e)
		{
			zelltypMenuComboBox.Items.Add("-- Zelltypen --");
			zelltypMenuComboBox.SelectedIndex = 0;
		}

		private void einstellungenToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (formPreferences.ShowDialog(this) == DialogResult.OK)
			{
				preferences = formPreferences.Preferences;
				cellTypes = formPreferences.CellDefinitions;
				colorsForCells = formPreferences.ColorsForCells;
				InitSimulation();
			}
		}

		private void zufallsverteilungToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (preferences == null)
			{
				MessageBox.Show("Bitte legen Sie erst Ihre Einstellungen fest.", "Keine Daten vorhanden", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
			}
			else
			{
				CreateRandomConfiguration();

			}
		}

		private void startToolStripMenuItem_Click(object sender, EventArgs e)
		{

			controller.StartSimulation(cells, preferences);
		}

		private void controller_StepCalculated(object sender, StepCalculatedEventArgs e)
		{
			this.cells = e.Field;
			//TODO Paint-Event starten
		}

		private void PanelField_MouseDown(object sender, MouseEventArgs e)
		{
			timerSetCells.Start();
		}

		private void PanelField_MouseUp(object sender, MouseEventArgs e)
		{
			timerSetCells.Stop();
		}

		private void timerSetCells_Tick(object sender, EventArgs e)
		{
			if (preferences != null && colorsForCells.ContainsKey(((CellDefinition)zelltypMenuComboBox.SelectedItem).ZellTyp))
			{
				ChangeCellAtLocation(Cursor.Position);
			}
		}

		private void panelField_Paint(object sender, PaintEventArgs e)
		{
			PaintField();
		}

		#endregion

		#region Work

		private void InitSimulation()
		{
			// Combobox for changing cellTypes in field manually
			InitComboboxForCellTypeSelection();

			InitField();

			InitEdgeLength();
		}

		private void InitComboboxForCellTypeSelection()
		{
			zelltypMenuComboBox.Items.Clear();
			foreach (var cellType in cellTypes)
			{
				zelltypMenuComboBox.Items.Add(cellType);
			}
			zelltypMenuComboBox.SelectedIndex = zelltypMenuComboBox.FindStringExact(cellTypes[0].ZellTyp);
		}

		private void InitField()
		{
			if (preferences.InitialField != null)
			{
				if (preferences.InitialField.GetLength(0) == preferences.SizeWidth && preferences.InitialField.GetLength(1) == preferences.SizeHeight)
				{
					this.cells = preferences.InitialField;
					return;
				}
				else
				{
					MessageBox.Show("Die initiale Belegung aus den geladenen Einstellungen konnte nicht gewählt werden, weil die Abmessungen des Feldes verändert wurden.",
						"Fehler bei Feldinitialisierung", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
				}
			}
			this.cells = new Cell[preferences.SizeWidth, preferences.SizeHeight];
			CreateRandomConfiguration();
		}

		private void InitEdgeLength()
		{
			//cells should be squares, so their edge length should be minimum
			int absHeight = panelField.Size.Height;
			int absWidth = panelField.Size.Width;
			cellEdgeLength = Math.Min((absHeight / preferences.SizeHeight), (absWidth / preferences.SizeWidth));
		}

		private void CreateRandomConfiguration()
		{
			Random random = new Random();
			for (int x = 0; x < cells.GetLength(0); x++)
			{
				for (int y = 0; y < cells.GetLength(1); y++)
				{
					int index = (int)(random.NextDouble() * cellTypes.Count);
					cells[x, y] = new Cell(cellTypes[index], new Point(x, y));
				}
			}
		}

		private void ChangeCellAtLocation(Point location)
		{
			Cell currentCell = MapLocationToCell(location);
			if (currentCell != null)
			{
				ChangeCell(ref currentCell);
			}
			panelField.Invalidate();
		}

		private Cell MapLocationToCell(Point location)
		{
			Point point = panelField.PointToClient(location);
			if (point.X >= 0 && point.X < cells.GetLength(0) * cellEdgeLength
				&& point.Y >= 0 && point.Y < cells.GetLength(1) * cellEdgeLength)
			{
				return cells[point.X / cellEdgeLength, point.Y / cellEdgeLength];
			}
			return null;
		}

		private void ChangeCell(ref Cell currentCell)
		{
			//TODO Funktionalität in Cell auslagern
			//außerdem müssen Attribute wahrscheinlich anders bearbeitet werden
			CellDefinition cellDef = (CellDefinition)zelltypMenuComboBox.SelectedItem;
			Point currentLoc = currentCell.Position;

			currentCell.init(cellDef);
		}

		private void PaintField()
		{
			panelField.SuspendLayout();
			if (cells == null)
			{
				return;
			}
			for (int x = 0; x < cells.GetLength(0); x++)
			{
				for (int y = 0; y < cells.GetLength(1); y++)
				{
					DrawCell(colorsForCells[cells[x, y].Name], panelField,
						new Point(x * cellEdgeLength, y * cellEdgeLength), new Size(cellEdgeLength, cellEdgeLength));
				}
			}
			panelField.PerformLayout();
		}

		private void DrawCell(Color color, Control control, Point location, Size size)
		{
			SolidBrush myBrush = new SolidBrush(color);
			Graphics formGraphics;
			formGraphics = control.CreateGraphics();
			formGraphics.FillRectangle(myBrush, new Rectangle(location, size));
			myBrush.Dispose();
			formGraphics.Dispose();
		}

		#endregion

	}
}
